<?php
/**
 * Created by PhpStorm.
 * User: MSQ
 * Date: 2021/9/24
 * Time: 14:27
 */

namespace App\Utils;

use EasySwoole\EasySwoole\Config;

class BaiduTts
{
    public $audioFileError = true;

    /**
     * 获取token
     * @param string $apiKey
     * @param string $secretKey
     * @return false|mixed
     */
    private function getAccessToken(string $apiKey, string $secretKey)
    {
        $redisHelp = new RedisHelp();
        $token = $redisHelp->getBaiduTtsToken();
        if ($token) {
            return $token;
        }

        /** 公共模块获取token开始 */
        // 填写网页上申请的appkey 如 $apiKey="g8eBUMSokVB1BHGmgxxxxxx"
//        $apiKey = "4E1BG9lTnlSeIf1NQFlrSq6h";
        // 填写网页上申请的APP SECRET 如 $secretKey="94dc99566550d87f8fa8ece112xxxxx"
//        $secretKey = "544ca4657ba8002e3dea3ac2f5fdd241";
        $auth_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=".$apiKey."&client_secret=".$secretKey;
        $res = Common::https_request($auth_url);

        $response = json_decode($res, true);

        if (!isset($response['access_token'])) {
            LogHelp::error('ERROR TO OBTAIN TOKEN', 'baidu');
            return false;
        }
        if (!isset($response['scope'])) {
            LogHelp::error('ERROR TO OBTAIN scopes', 'baidu');
            return false;
        }
        if (!in_array('audio_tts_post',explode(" ", $response['scope']))) {
            LogHelp::error('DO NOT have tts permission', 'baidu');
            // 请至网页上应用内开通语音合成权限
            return false;
        }

//        $token = $response['access_token'];
//        print_r($res);

        // {"refresh_token":"25.aabe4c65cf96ba3853227cb9db22e39b.315360000.1960772442.282335-25627925","expires_in":2592000,"session_key":"9mzdA8hELK1Vcg8VOp4s7oKCXEy0MGa9efDa\/Tn6Tt9kDx2vyNh82oQnmF9hhsuZeg3SmF4tFdSTo3Tegldi+Z+lqGaDTw==","access_token":"24.8b2b15cbf44d3fbde106434d468627ff.2592000.1648004442.282335-25627925","scope":"audio_voice_assistant_get brain_enhanced_asr audio_tts_post brain_speech_realtime public brain_all_scope brain_asr_async wise_adapt lebo_resource_base lightservice_public hetu_basic lightcms_map_poi kaidian_kaidian ApsMisTest_Test\u6743\u9650 vis-classify_flower lpq_\u5f00\u653e cop_helloScope ApsMis_fangdi_permission smartapp_snsapi_base smartapp_mapp_dev_manage iop_autocar oauth_tp_app smartapp_smart_game_openapi oauth_sessionkey smartapp_swanid_verify smartapp_opensource_openapi smartapp_opensource_recapi fake_face_detect_\u5f00\u653eScope vis-ocr_\u865a\u62df\u4eba\u7269\u52a9\u7406 idl-video_\u865a\u62df\u4eba\u7269\u52a9\u7406 smartapp_component smartapp_search_plugin avatar_video_test b2b_tp_openapi b2b_tp_openapi_online","session_secret":"1ef53b7fc4d3be366169aca0ccc2703e"}
        $redisHelp->setBaiduTtsToken($response['access_token'], $response['expires_in'] - 1000);

        return $response['access_token'];
    }

    /**
     * @param string $text
     * @return string
     */
    public function getAudioFile(string $text)
    {
        $config = Config::getInstance()->getConf("BAIDU_TTS");
        $token = $this->getAccessToken($config['apiKey'], $config['secretKey']);
        if ($token === false) {
            return '';
        }

        # text 的内容为"欢迎使用百度语音合成"的urlencode,utf-8 编码
        # 可以百度搜索"urlencode"
//        $text = "请五诊光头强到肌肉注射室进行输液";
//        $text = "请五诊HAROON RASHEED到肌肉注射室进行输液";

        // 发音人选择, 基础音库：0为度小美，1为度小宇，3为度逍遥，4为度丫丫，
        // 精品音库：5为度小娇，103为度米朵，106为度博文，110为度小童，111为度小萌，默认为度小美
        $per = 0;
        // 语速，取值0-15，默认为5中语速
        $spd = 4;
        // 音调，取值0-15，默认为5中语调
        $pit = 5;
        // 音量，取值0-9，默认为5中音量
        $vol = 9;
        // 下载的文件格式, 3：mp3(default) 4： pcm-16k 5： pcm-8k 6. wav
        $aue = 3;

        $formats = array(3 => 'mp3', 4 => 'pcm', 5 =>'pcm', 6 => 'wav');
        $format = $formats[$aue];

        $cuid = "123456PHP";

        /** 拼接参数开始 **/
        // tex=$text&lan=zh&ctp=1&cuid=$cuid&tok=$token&per=$per&spd=$spd&pit=$pit&vol=$vol
        $params = [
            'tex' => urlencode($text), // 为避免+等特殊字符没有编码，此处需要2次urlencode。
            'tok' => $token,
            'per' => $per,
            'spd' => $spd,
            'pit' => $pit,
            'vol' => $vol,
            'aue' => $aue,
            'cuid' => $cuid,
            'lan' => 'zh', //固定参数
            'ctp' => 1, // 固定参数
        ];
        $paramsStr =  http_build_query($params);
        $url = 'https://tsn.baidu.com/text2audio';
//        $urltest = $url . '?' . $paramsStr;
//        echo $urltest . "\n"; // 反馈请带上此url

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt ($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsStr);
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($ch, $header) {
            $comps = explode(":", $header);
            // 正常返回的头部 Content-Type: audio/*
            // 有错误的如 Content-Type: application/json
            if (count($comps) >= 2){
                if (strcasecmp(trim($comps[0]), "Content-Type") == 0){
                    if (strpos($comps[1], "audio/") > 0 ){
                        $this->audioFileError = false;
                    }
                }
            }
            return strlen($header);
        });
        $data = curl_exec($ch);
        if(curl_errno($ch)) {
            LogHelp::error(curl_error($ch), 'baidu');
            return '';
        }

        curl_close($ch);

        if ($this->audioFileError) {
            // {"err_detail":"16: Open api characters limit reached","err_msg":"16: Open api characters limit reached","err_no":502,"err_subcode":16,"tts_logid":237661760}
            LogHelp::error($data, 'baidu');
            return false;
        }

        $date = date('Ymd');
        $time = date('His');

        $dir = $config['filePath']."/{$date}";
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
        $fileName = "tmp_{$date}{$time}.".$format;
        file_put_contents($dir."/".$fileName, $data);

//        print_r($data);

        return "tmp/{$date}/{$fileName}";
    }
}
